/**
 * @author: mattwang@tencent.com
 * @date: 2012-10-20
 */

#ifndef __SVD_TRAINER_H__
#define __SVD_TRAINER_H__

#include "svd_data.h"
#include "svd_model.h"

using namespace apex_tensor;

class SvdTrainer {
public:
	SvdTrainer();
	void load_model(FILE *fi);
	void save_model(FILE *fo);
	void init_model(void);
	void init_trainer(void);
public:
	void update(const ReDataBlock &data);
	void predict(std::vector<float> &pred, const ReDataBlock &data);
	void global_sync_model();

public:
	~SvdTrainer();

private:
	void reg_global(const unsigned gid);
	void reg_user(const unsigned uid);
	void reg_item(const unsigned iid);
	void regularize(const ReData::Sample feature);
	double calc_bias(const ReData::Sample &feature, const CTensor1D &u_bias, const CTensor1D &i_bias,
			const CTensor1D &g_bias);
	void prepare_tmp(const ReData::Sample &feature);
	float predict(const ReData::Sample &feature);
	void update_no_decay(const ReData::Sample &feature);
	void update_inner(const ReData::Sample &feature);
	void prepare_ufeedback(const ReDataBlock &data);
	void update_ufeedback(const ReDataBlock &data);

private:
	SvdModel snapshot_model;
	SvdModel local_model;
	CTensor1D tmp_ufactor, tmp_ifactor;

private:
	int round_counter;
private:
// data structure used for lazy decay
	unsigned sample_counter;
	unsigned *ref_user, *ref_item, *ref_global;
private:
// SVD++ style
	float norm_ufeedback;
	float tmp_ufeedback_bias, old_ufeedback_bias;
	CTensor1D tmp_ufeedback, old_ufeedback;

private:
	SvdModel sum_model;
	CTensor1D sum_ufeedback;
	double sum_ufeedback_bias;
	int sum_sample_count;
	unsigned *sum_item;
};

#endif		// __SVD_TRAINER_H__
